﻿using ChoJu.ModelManager.Config;
using ChongJu.GlobalInfo;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Threading;

namespace ChoJu.Single.DAL
{
    public class SerialPortDal
    {
        private static readonly object _obj = new object();
        private static SerialPortDal _instance;
        public static SerialPortDal Instance
        {
            get
            {
                if (_instance == null)
                    lock (_obj)
                        if (_instance == null)
                            _instance = new SerialPortDal();

                return _instance;
            }
        }

        private WeightConfigModel _config;

        SerialPort _serialPort;
        WeiCalca _calca;
        private bool _read = false;
        public double _result = -100;

        private bool _isRead = false;
        private bool _isAllowRead = true; //是否允许实时读取重量信息

        private List<double> _views = new List<double>();

        public bool Init(WeightConfigModel cfg)
        {
            try
            {
                _config = cfg;
                _calca = new WeiCalca(cfg.Count, cfg.SmoothCount, cfg.Change);
                Parity parity = Parity.None;   // 校验位
                int dataBits = 8;              // 数据位
                StopBits stopBits = StopBits.One; // 停止位

                if (_serialPort == null)
                {
                    _serialPort = new SerialPort(cfg.ComName, cfg.BaudRate, parity, dataBits, stopBits);
                    _serialPort.Open();
                    _read = true;
                }
                else
                {
                    _read = false;
                    Thread.Sleep(1000);
                    _serialPort.Close();
                    _serialPort = new SerialPort(cfg.ComName, cfg.BaudRate, parity, dataBits, stopBits);
                    _serialPort.Open();
                    _read = true;
                }
            }
            catch(Exception ex)
            {

            }

            Task.Run(() =>
            {
                try
                {
                    while (_read)
                    {
                        if(_isAllowRead == false)
                        {
                            Thread.Sleep(100);
                            continue;
                        }

                        // 读取保持寄存器
                        var result = ReadHoldingRegisters(_serialPort);
                        if (result == -1 || _isRead == true)
                            continue;

                        _result = _calca.InputNew(result);
                    }
                }
                catch (Exception ex)
                {
                }
            });

            return true;
        }

        /// <summary>
        /// 读取保持寄存器 (功能码 03)
        /// </summary>
        /// <param name="serialPort">串口对象</param>
        /// <param name="slaveAddress">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="numRegisters">要读取的寄存器数量</param>
        /// <returns>读取到的寄存器值数组</returns>
        float ReadHoldingRegisters(SerialPort serialPort)
        {
            // 清空接收缓冲区
            serialPort.DiscardInBuffer();

            // 发送请求
            byte[] cmd = new byte[8] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B };
            //cmd = MakeRequest(26, 25, 2);
            serialPort.Write(cmd, 0, 8);

            // 等待响应 (根据设备响应时间调整)
            Thread.Sleep(_config.Interval);

            // 读取响应
            int bytesToRead = serialPort.BytesToRead;
            byte[] response = new byte[bytesToRead];
            serialPort.Read(response, 0, bytesToRead);

            // 验证响应
            if (response.Length < 5)
                return -1;

            if (response[0] != 0x01) //0x01为地址
                return -1;

            if (response[1] != 0x03)
                return -1;

            if (response.Length < 8)
                return -1;

            var data = new byte[4] { response[4], response[3], response[6], response[5] };
            var temp = BitConverter.ToInt32(data, 0);
            var rate = GlobalVar.GlobalParamer.WeightType == 2 ? 10f : 100f;
            var result = temp / rate;

            //if (result > 50)
            //    return -1;
            _views.Add(Math.Round(result, 1));
            return result;
        }

        public byte[] MakeRequest(byte slaveAddress, ushort startAddress, ushort numRegisters)
        {
            // 创建请求报文
            byte[] request = new byte[8];
            request[0] = slaveAddress;              // 从站地址
            request[1] = 0x03;                      // 功能码: 读取保持寄存器
            request[2] = (byte)(startAddress >> 8); // 起始地址高字节
            request[3] = (byte)(startAddress);      // 起始地址低字节
            request[4] = (byte)(numRegisters >> 8); // 寄存器数量高字节
            request[5] = (byte)(numRegisters);      // 寄存器数量低字节

            // 计算CRC校验
            ushort crc = CalculateCRC1(request, 6);
            request[6] = (byte)(crc & 0xFF);        // CRC低字节
            request[7] = (byte)(crc >> 8);          // CRC高字节

            return request;
        }

        /// <summary>
        /// 计算Modbus CRC16校验码
        /// </summary>
        /// <param name="data">要计算的数据</param>
        /// <param name="length">数据长度</param>
        /// <returns>CRC16校验码</returns>
        ushort CalculateCRC1(byte[] data, int length)
        {
            ushort crc = 0xFFFF;

            for (int i = 0; i < length; i++)
            {
                crc ^= data[i];

                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) == 1)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }

            return crc;
        }

        public double GetWeight()
        {
            //_isRead = true;
            while (_result == -100)
                Thread.Sleep(_config == null ? 1000 : _config.Interval);

            //_calca.Test(_result);
            //_isRead = false;
            return _result;
        }

        public double GetCurrentWeight()
        {
            if (_calca == null)
                return 0;

            return _calca.GetCurrentWeight();
        }

        public bool Pleed()
        {
            //var file = Path.Combine(AppContext.BaseDirectory, "data", $"{DateTime.Now.ToString("HHmmss")}_weight.txt");
            //StringBuilder sb = new StringBuilder();
            //foreach(var item in _views)
            //    sb.Append(item.ToString()).Append(" ");
            //File.WriteAllText(file, sb.ToString());
            //return true;

            var cmd = new byte[] { 0x01, 0x06, 0x00, 0x15, 0x00, 0x01, 0x59, 0xCE };
            _serialPort.Write(cmd, 0, cmd.Length);

            _result = ReadHoldingRegisters(_serialPort);

            return true;
        }

        public void SetRead(bool read)
        {
            _isAllowRead = read;
        }

        public void Zero()
        {
            //关闭写保护，允许写入
            var cmd = new byte[] { 0x01, 0x06, 0x00, 0x17, 0x00, 0x01, 0xF8, 0x0E };
            _serialPort.Write(cmd, 0, cmd.Length);
            Thread.Sleep(200);

            //零点校准
            cmd = new byte[] { 0x01, 0x06, 0x00, 0x16, 0x00, 0x01, 0xA9, 0xCE };
            _serialPort.Write(cmd, 0, cmd.Length);
            Thread.Sleep(200);

            //打开写保护，不允许写入
            cmd = new byte[] { 0x01, 0x06, 0x00, 0x17, 0x00, 0x00, 0x39, 0xCE };
            _serialPort.Write(cmd, 0, cmd.Length);

            Thread.Sleep(200);
            _result = ReadHoldingRegisters(_serialPort);
        }

        public void WeightWrite(int weight)
        {
            //关闭写保护，允许写入
            var cmd = new byte[] { 0x01, 0x06, 0x00, 0x17, 0x00, 0x01, 0xF8, 0x0E };
            _serialPort.Write(cmd, 0, cmd.Length);
            Thread.Sleep(200);

            //重量校准
            var req = new byte[] { 0x01, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 };
            byte[] bytes = BitConverter.GetBytes((ushort)weight);
            req[4] = bytes[1];
            req[5] = bytes[0];

            ushort crc = CalculateCRC1(req, 6);
            req[6] = (byte)(crc & 0xFF);        // CRC低字节
            req[7] = (byte)(crc >> 8);          // CRC高字节

            _serialPort.Write(req, 0, cmd.Length);
            Thread.Sleep(200);

            //打开写保护，不允许写入
            cmd = new byte[] { 0x01, 0x06, 0x00, 0x17, 0x00, 0x00, 0x39, 0xCE };
            _serialPort.Write(cmd, 0, cmd.Length);

            Thread.Sleep(200);
            _result = ReadHoldingRegisters(_serialPort);
        }
    }
}
